from PyQt4.QtOpenGL import *
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *

from common import *
from mapeditor.core.memanager import MEManager
from common.GLUtil.mouse import Mouse
from common.doodads.nanmine import NandocariumMine
from common.buildings.workopolis import Workopolis

class GlWidget(QGLWidget):
	"""
	Implementation of the QGLWidget widget.
	"""
	def __init__ (self, parent):
		"""
		Widget constructor.
		"""
		
		super(GlWidget, self).__init__(parent)
		
		# Initialize window-related attributes.
		self.wWidth, self.wHeight = 0, 0
		
		# Initialize mouse object.
		self.mouse = Mouse()
		self.setMouseTracking(True)
		
	def initializeGL(self):
		"""
		Method called right before the first paintGL() or resizeGL() call.
		"""
		
		glEnable(GL_DEPTH_TEST)
		glEnable(GL_BLEND)
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
		
		MEManager.load_models()
		
		# Lighting
		glEnable(GL_LIGHTING)
		MEManager.lighting.addLight(GL_LIGHT0)
		MEManager.lighting.setLight(GL_LIGHT0, [1.0, 1.0, 1.0, 0],
										[0.4, 0.7, 0.9, 1],
										[0.2, 0.9, 0.6, 1])
		
		glEnable(GL_COLOR_MATERIAL)
		glMaterial(GL_FRONT_AND_BACK, GL_SPECULAR, [1, 1, 1])
		glMaterial(GL_FRONT_AND_BACK, GL_SHININESS, 20)
		glClearColor(0, 0.1, 0.3, 1)
		
	def paintGL(self):
		"""
		Widget drawing callback.
		"""
		
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
		self.render()

	def resizeGL (self, width, height):
		"""
		Resize callback.
		"""
		
		self.wWidth, self.wHeight = width, height
		glViewport(0, 0, width, height)
		self.updateGL()

	def mouseMoveEvent(self, ev):
		"""
		Mouse movement callback.
		"""
		
		self.updateMousePosition()
		if MEManager.edition_mode == MEManager.SCENARIO:
			MEManager.hovered = []
			overBlock = MEManager.map.terrain.tryPick(MEManager.camera,
											self.mouse[X], self.mouse[Y])
			if overBlock is None: return
			
			center = overBlock.id
			lim_x = range(center[X] - MEManager.range + 1, center[X] + MEManager.range)
			lim_y = range(center[Y] - MEManager.range + 1, center[Y] + MEManager.range)
			for i in lim_x:
				if i < 0 or i > MEManager.map.terrain.width - 1: continue
				for j in lim_y:
					if j < 0 or j > MEManager.map.terrain.height - 1: continue
					MEManager.hovered.append(MEManager.map.terrain.blocks[i][j])
			self.updateGL()
			
		elif MEManager.edition_mode == MEManager.UNITS:
			block = MEManager.map.terrain.tryPick(MEManager.camera,
										self.mouse[X], self.mouse[Y])
			
			if not(block is None):
				if MEManager.adding is None:
					MEManager.hovered = block.occupation
				else:
					MEManager.hovered = block
				
			self.updateGL()
			
		elif MEManager.edition_mode == MEManager.BUILDINGS:
			block = MEManager.map.terrain.tryPick(MEManager.camera,
										self.mouse[X], self.mouse[Y])
			
			if not(block is None):
				if MEManager.adding is None:
					MEManager.hovered = block.occupation
				else:
					MEManager.hovered = block
					
			self.updateGL()
			
		elif MEManager.edition_mode == MEManager.DOODADS:
			block = MEManager.map.terrain.tryPick(MEManager.camera,
										self.mouse[X], self.mouse[Y])
			
			if not(block is None):
				if MEManager.adding is None:
					MEManager.hovered = block.occupation
				else:
					MEManager.hovered = block
					
			self.updateGL()
		
	def mousePressEvent(self, ev):
		"""
		Mouse press callback.
		"""
		
		#self.updateMousePosition()
		btn = ev.button()
		
		if (btn == Qt.LeftButton):
			if MEManager.edition_mode == MEManager.SCENARIO:
				MEManager.selected = MEManager.hovered
				self.updateGL()
				
			elif MEManager.edition_mode == MEManager.UNITS:
				selected = MEManager.selected
				
				if MEManager.adding is None:
					# Not adding anything.
					MEManager.selected = MEManager.hovered
					self.updateGL() 
				else:
					# Adding an unit.
					if selected is None: return
					if not(MEManager.map.terrain.can_build(selected.top_left_block, *selected.SIZE)):
						return
					
					MEManager.map.units.append(MEManager.selected)
					MEManager.map.terrain.occupy(selected)
					MEManager.adding = None
					MEManager.hovered = None
					MEManager.selected = None
					self.updateGL()
				
			elif MEManager.edition_mode == MEManager.BUILDINGS:
				selected = MEManager.selected
				
				if MEManager.adding is None:
					# Not adding anything.
					MEManager.selected = MEManager.hovered
					self.updateGL() 
				else:
					# Adding a building.
					if selected is None: return
					if not(MEManager.map.terrain.can_build(selected.top_left_block, *selected.SIZE)):
						return
					
					MEManager.map.buildings.append(MEManager.selected)
					MEManager.map.terrain.occupy(selected)
					MEManager.adding = None
					MEManager.hovered = None
					MEManager.selected = None
					self.updateGL()
				
			elif MEManager.edition_mode == MEManager.DOODADS:
				selected = MEManager.selected
				
				if MEManager.adding is None:
					# Not adding anything.
					MEManager.selected = MEManager.hovered
					self.updateGL() 
				else:
					# Adding a doodad.
					if selected is None: return
					if not(MEManager.map.terrain.can_build(selected.top_left_block, *selected.SIZE)):
						return
					
					MEManager.map.doodads.append(MEManager.selected)
					MEManager.map.terrain.occupy(selected)
					MEManager.adding = None
					MEManager.hovered = None
					MEManager.selected = None
					self.updateGL()
			
		elif (btn == Qt.RightButton):
			print "Right"
		
	def mouseReleaseEvent(self, ev):
		"""
		Mouse release callback.
		"""
		
		self.updateMousePosition()

	def enterEvent(self, ev):
		"""
		Event called when the mouse enters the widget area.
		"""
		
		self.setFocus()
		self.grabKeyboard()
		
	def leaveEvent(self, ev):
		"""
		Event called when the mouse leaves the widget area.
		"""
		
		self.parent().setFocus()
		self.releaseKeyboard()

	def keyPressEvent(self, ev):
		"""
		Key press callback.
		"""
		
		key = str(ev.text()).upper()
		
		if (key == "T"):
			self.updateGL()
		elif (ev.key() == Qt.Key_Up):
			MEManager.camera.position += MEManager.camera.upVector * 0.2
			self.updateGL()
		elif (ev.key() == Qt.Key_Down):
			MEManager.camera.position -= MEManager.camera.upVector * 0.2
			self.updateGL()
		elif (ev.key() == Qt.Key_Left):
			MEManager.camera.position += MEManager.camera.leftVector * 0.2
			self.updateGL()
		elif (ev.key() == Qt.Key_Right):
			MEManager.camera.position -= MEManager.camera.leftVector * 0.2
			self.updateGL()
		
	def keyReleaseEvent(self, ev):
		"""
		Key release callback.
		"""
		
		pass
			
	def updateMousePosition(self):
		"""
		Updates mousePos and lastMousePos attributes, using GL coordinates.
		"""
		
		screenY = self.mapFromGlobal(QCursor.pos()).y()
		
		self.mouse.lastPosition[X] = self.mouse[X]
		self.mouse.lastPosition[Y] = self.mouse[Y]
		
		self.mouse[X] = self.mapFromGlobal(QCursor.pos()).x()
		self.mouse[Y] = glGetIntegerv(GL_VIEWPORT)[3] - screenY - 1
			
	def render(self):
		"""
		Renders the scene.
		Warning: This method sets the matrix mode to GL_MODELVIEW.
		"""
		
		# Camera
		MEManager.camera.setLens(float(self.wWidth) / self.wHeight)
		MEManager.camera.setView()
		
		MEManager.map.terrain.render(True)
		
		if MEManager.edition_mode == MEManager.SCENARIO:
			if not(MEManager.hovered is None):
				for block in MEManager.hovered:
					block.render_hovered()
			if not(MEManager.selected is None):
				for block in MEManager.selected:
					block.render_selected()
					
		elif MEManager.edition_mode == MEManager.UNITS:
			hovered = MEManager.hovered
			selected = MEManager.selected
			chosen_class = MEManager.adding
			
			if chosen_class is None:
				# Not adding anything.
				if not(selected is None):
					glDisable(GL_DEPTH_TEST)
					selected.render_selection()
					glEnable(GL_DEPTH_TEST) 
			else:
				# Adding an unit.
				if not(hovered is None) and \
					MEManager.map.terrain.can_fit(hovered, *chosen_class.SIZE):
					
					MEManager.selected = chosen_class(hovered, MEManager.team)
					MEManager.selected.render(0.7)
				else:
					MEManager.selected = None
					
		elif MEManager.edition_mode == MEManager.BUILDINGS:
			hovered = MEManager.hovered
			selected = MEManager.selected
			chosen_class = MEManager.adding
			
			if chosen_class is None:
				# Not adding anything.
				if not(selected is None):
					glDisable(GL_DEPTH_TEST)
					selected.render_selection()
					glEnable(GL_DEPTH_TEST) 
			else:
				# Adding a building.
				if not(hovered is None) and \
					MEManager.map.terrain.can_fit(hovered, *chosen_class.SIZE):
					
					MEManager.selected = chosen_class(hovered, MEManager.team)
					MEManager.selected.render(0.7)
				else:
					MEManager.selected = None
		
		elif MEManager.edition_mode == MEManager.DOODADS:
			hovered = MEManager.hovered
			selected = MEManager.selected
			chosen_class = MEManager.adding
			
			if chosen_class is None:
				# Not adding anything.
				if not(selected is None):
					glDisable(GL_DEPTH_TEST)
					selected.render_selection()
					glEnable(GL_DEPTH_TEST) 
			else:
				# Adding a doodad.
				if not(hovered is None) and \
					MEManager.map.terrain.can_fit(hovered, *chosen_class.SIZE):
					
					MEManager.selected = chosen_class(hovered, MEManager.team)
					MEManager.selected.render(0.7)
				else:
					MEManager.selected = None
					
		for unit in MEManager.map.units:
			unit.render()
			
		for building in MEManager.map.buildings:
			building.render()
			
		for doodad in MEManager.map.doodads:
			doodad.render()